package cn.eric.framework.utils.general.merge;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;

public class EMerge {
    private EMerge() {
    }

    public static <BASE, NEW> BASE overwrite(BASE base, NEW _new) {
        // to check null
        if (base == null || _new == null) {
            return base;
        }
        Class nClazz = _new.getClass();
        Class bClazz = base.getClass();

        // to check patch Interface and target clazz
        if (!Arrays.asList(nClazz.getInterfaces()).contains(EMergePatch.class)) {
            throw new NotPatchOrNotSuitableTargetException(nClazz);
        }
        if (!((EMergePatch) _new).getTargetClass().equals(bClazz)) {
            throw new NotPatchOrNotSuitableTargetException(nClazz, bClazz);
        }

        ArrayList<Field> fields = new ArrayList<>();
        Class clazz = bClazz;
        while (clazz != null) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            clazz = clazz.getSuperclass();
        }

        for (Field bField : fields) {
            // to check is exposed
            if (bField.getAnnotation(EMergeExpose.class) == null) {
                try {
                    Field newField = nClazz.getDeclaredField(bField.getName());
                    if (newField.getAnnotation(EMergeExpose.class) == null) {
                        bField.setAccessible(true);
                        newField.setAccessible(true);
                        bField.set(base, newField.get(_new));
                    }
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    continue;
                }
            }
        }
        return base;
    }

    public static void main(String[] args) {
    }
}
